﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System.Xml.Schema;
using System.Xml.Xsl;

namespace JoomlaXMLEditor
{
    public class TemplateXML
    {
        /// <summary>
        /// Uchwyt do głównego okna aplikacji
        /// </summary>
        public MainWindow parent;
        public bool isValid;
        public String DTDErrors;
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="parent"></param>
        public TemplateXML(MainWindow parent) 
        {
            this.parent = parent;
            this.isValid = true;
            this.DTDErrors = "";
        }
        /// <summary>
        /// Metoda wczytująca plik XML
        /// </summary>
        /// <param name="XMLTree">Uchwyt do drzewa w oknie głównym</param>
        /// <param name="filename">Nazwa pliku do wczytania</param>
        public void loadFile(TreeView XMLTree, String filename)
        {
            // Czyścimy drzewo dokumentu
            XMLTree.Nodes.Clear();
            // Tworzymy dokument XML
            this.parent.actualFile = new XmlDocument();
            // Próba wczytania pliku XML
            try
            {
                this.parent.actualFile.Load(filename);
            }
            catch (Exception e) // obsługa wyjątków
            {
                MessageBox.Show(e.Message);
                this.parent.actualFile = null;
                return;
            }

            if (this.validateDTD(filename))
            {
                // Konwertujemy drzewo dokumentu na TreeView
                ConvertXmlNodeToTreeNode(this.parent.actualFile, XMLTree.Nodes);
                // Rozwijamy wszystkie elementy podrzędne korzenia
                XMLTree.Nodes[0].ExpandAll();
            }
            else
            {
                this.parent.actualFile = null;
                MessageBox.Show("Podany plik XML nie jest zgodny z DTD pliku instalatora szablonu dla Joomla!\n Znalezione błędy:\n" + this.DTDErrors);
            }
        }
        /// <summary>
        /// Metoda konwertująca plik XML na drzewo TreeView
        /// </summary>
        /// <param name="XMLNode">Węzeł do przetworzenia rekurencyjnego</param>
        /// <param name="treeNodes">Uchwyt do węzłów w drzewie okna głównego</param>
        private void ConvertXmlNodeToTreeNode(XmlNode XMLNode, TreeNodeCollection treeNodes)
        {
            // pominięcie wybranych typów węzłów
            if (XMLNode.NodeType != XmlNodeType.Text &&
                XMLNode.NodeType != XmlNodeType.Attribute &&
                XMLNode.NodeType != XmlNodeType.Comment &&
                XMLNode.NodeType != XmlNodeType.XmlDeclaration &&
                XMLNode.NodeType != XmlNodeType.CDATA &&
                XMLNode.NodeType != XmlNodeType.ProcessingInstruction && 
                XMLNode.NodeType != XmlNodeType.DocumentType)
            {
                // stworzenie nowego drzewa
                TreeNode newTreeNode = treeNodes.Add(XMLNode.Name);
                // sprawdzenie typu węzła
                if(XMLNode.NodeType == XmlNodeType.Element)
                {
                    // tworzenie treści węzła
                    newTreeNode.Text = "<" + XMLNode.Name;
                    // listowanie atrybutów
                    if (XMLNode.Attributes != null)
                    {
                        // przetwarzanie atrybutów w pętli
                        foreach (XmlAttribute attribute in XMLNode.Attributes)
                        {
                            newTreeNode.Text += " " + attribute.Name + "=\"" + attribute.Value + "\"";
                        }
                    }
                    // iterowanie po węzłach potomnych
                    if (XMLNode.ChildNodes.Count == 1 &&
                        (XMLNode.ChildNodes[0].NodeType == XmlNodeType.Text ||
                         XMLNode.ChildNodes[0].NodeType == XmlNodeType.CDATA))
                    {
                        // gdy istnieje węzeł potommny
                        newTreeNode.Text += ">";
                        newTreeNode.Text += XMLNode.ChildNodes[0].Value;
                        newTreeNode.Text += "</" + XMLNode.Name + ">";
                    }
                    else
                    {
                        // gdy istnieje więcej węzłów potomnych
                        if (XMLNode.ChildNodes.Count > 1)
                        {
                            newTreeNode.Text += ">";
                        }
                        else // gdy brak węzłów potomnych i treści
                        {
                            newTreeNode.Text += "/>";
                        }
                    }
                }
                // przetwarzanie kolejnych węzłów rekurencyjnie
                foreach (XmlNode childNode in XMLNode.ChildNodes)
                {
                    ConvertXmlNodeToTreeNode(childNode, newTreeNode.Nodes);
                }
            }
        }
        // walidacja DTD
        private bool validateDTD(String filename)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ProhibitDtd = false;
            settings.ValidationType = ValidationType.DTD;
            settings.ValidationEventHandler += new ValidationEventHandler(MyValidationEventHandler);
            // tworzenie obiektu xml reader
            XmlReader reader = XmlReader.Create(filename, settings);
            // parsowanie pliku
            while (reader.Read());
            // zwrócenie rezultatu
            return this.isValid;
        }
        // metoda walidująca
        private void MyValidationEventHandler(object sender, ValidationEventArgs args)
        {
            // gdy plik niepoprawny
            this.isValid = false;
            this.DTDErrors += " * " + args.Message + "\n";
        }
        // zapis pliku
        public void saveFile(String filename)
        {
            // próba zapisu pliku
            try
            {
                this.parent.actualFile.Save(filename);
            }
            catch (Exception e) // obsługa wyjątków
            {
                MessageBox.Show(e.Message);
                return;
            }
        }
        // odświeżanie drzewa
        public void refreshTree(TreeView XMLTree, XmlDocument document)
        {
            // Czyścimy drzewo dokumentu
            XMLTree.Nodes.Clear();
            // Konwertujemy drzewo dokumentu na TreeView
            ConvertXmlNodeToTreeNode(this.parent.actualFile, XMLTree.Nodes);
            // Rozwijamy wszystkie elementy podrzędne korzenia
            XMLTree.Nodes[0].ExpandAll();
        }
        // transformacja do XHTML poprzez XSLT
        public void transformToXHTML(String input, String output)
        {
            // próba wykonana transformacji XSLT do XHTML
            try
            {
                XslTransform transform = new XslTransform();
                transform.Load("transformacjaXHTML.xslt");
                transform.Transform(input, output);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
    }
}
